Getting started with Tezos: first steps

October 20, 2017
easy cryptocurrency tezos michelson blockchain smart contracts

July 30th 2018: Tezos betanet has now launched, and this article doesn’t reflect the current state of the project. You can still read through it, but the code examples won’t work as is, and will need various changes. Up to date documentation for the betanet is available here. You can change the address to access docs for other branches like zeronet.

A word about different testnets: there is usually a zeronet running, which follows new developments closely and an alphanet which is more stable. The real network is currently called betanet (transactions persist to the main network). The alphanet is currently obsolete.


What’s Tezos?

There’s been a surge of interest in Bitcoin, as its price rose dramatically over the last few months, and cryptocurrencies in general. Besides Bitcoin, the most significant cryptocurrency in terms of market cap is Ethereum, loosely followed by Litecoin, Ripple and Bitcoin Cash (a recent fork of Bitcoin). Ethereum is interesting, because it also offers smart contract capabilities – those can be used to build various services – a few ideas include transparent gambling or automated insurance providers. There have been some issues, however, with Ethereum smart contracts getting hacked, which leads to financial losses and makes potential users wary of blockchain technology as a whole. Ethereum smart contracts are usually written in a language called Solidity, which looks similar to Javascript and will feel familiar to many people on one hand, but on the other hand is riddled with bad design decisions and subtle gotchas that increase the likelihood of mistakes.

Some of these concerns have been addressed by Tezos – a new cryptocurrency that’s been publicized recently on account of a very successful fundraiser this July. Tezos is written in the functional language OCaml, which has a robust type system, making it easier to debug and maintain. Their smart contract language (called Michelson), is statically typed and designed with security in mind, to help avoid common errors that could be used to attack a contract. The language should lend itself to formal verification, which can be used to prove e.g. that a contract only sends out at most the same amount of money it receives (which helps against hackers attempting to steal money contained in a contract) or other properties of interest.

In this article, we will cover setting up a Tezos alphanet node and writing basic contracts in Michelson, look at various resources to help us learn Michelson, typecheck the contracts we write and finally run them.


Setting up a node

As of April 2018, the zeronet should be used instead of the alphanet, as it has many improvements. Note that the zeronet is changing quite often, but there should be an updated stable testnet available in a few weeks.

There are a few ways to get an alphanet node up and running, but the easiest one is to use the provided docker image. For this we will need to have a recent version of docker installed. If your repository has an outdated version, add the docker official repo and install it from there. Instructions are available here.

After you have docker installed, follow the instructions here to download the alphanet script and run it. It will run a node and synchronize with the rest of the network. It can take a while to crunch the numbers before it gets to the latest block, so it might make sense to let it run in the background while doing something else. A few common issues are also described there, so check that first if something doesn’t work. Check that an account has been created for you with:

./alphanet.sh client get balance for my_account

If this gives you an error, check the Known Issues section on how to create a new account and give it money manually.


Michelson

Michelson is a stack based language, inspired by Forth, ML, Scheme and others. If you aren’t familiar with those languages, don’t worry – it’s quite easy and might remind you of coding in assembly (there are no registers though). All functions take the current state of the stack as the input, and output the resulting stack. The language specification is available here. It may look a bit intimidating, but it really just lists all the data types & instructions, what needs to be on the top of the stack when calling them and what’s the resulting state of the stack. It’s a good idea to check the specification while reading contract code, to get familiar with new instructions.

The try-michelson REPL by Dan Robinson should help you understand more complicated constructs or instructions. You can get similar output using the command line client as well, with the typecheck command:

./alphanet.sh client typecheck program container:path/to/myContract.tz

You can also check data literals:

./alphanet.sh client typecheck data "hello" against type string

One of the best sources of information for learning Michelson is the michelson-lang website by Milo Davis. The “A contract a day” series is a good way to pick up the principles of writing Michelson contracts.


Hello World

Let’s start with a simple Hello World contract. All contracts must specify the type of storage, parameters and return value. If we don’t need to use storage, we can use the placeholder type unit (you can think of it as void in C and similar languages). Likewise, we have to specify the type of the input parameters. Since we want our contract to just output a hard coded phrase, we don’t need any parameters either and will use unit. The contract will return a string, and the compiler will let us know if we accidentally try to return something else. The contract header now looks like this:

parameter unit;
return string;
storage unit;

The stack at the beginning of contract execution has a pair containing the parameter and the storage.

[ pair unit unit ]

At the end of contract execution, the compiler expects to find a similar pair, containing the return value and the storage and we will get an error if the types don’t match.

Besides the header, the contract also contains some code to be executed. The code can be zero or more instructions that manipulate the stack and ideally do something useful. At the beginning, we have a pair containing the input and storage. We can use CAR and CDR to access the first or second element of the pair. We’d like to output a string, so we’ll use the PUSH instruction to push a string onto the stack. We don’t care about the storage, but the compiler expects to see a pair of return value and storage, so we’ll use the PAIR instruction to form a pair.

code {CDR;PUSH string "Hello World!";PAIR}

The whole contract looks like this:

parameter unit;
return string;
storage unit;
code {CDR;PUSH string "Hello World!";PAIR}

Try running it in the try-michelson REPL. You’ll need to specify the starting storage and the input – since we are using the unit type, you need to use the placeholder value Unit for them. In the “Typecheck” tab, you can see the types of elements on the stack after each instruction.

Try changing the contract so that it returns a stored string instead. You can change the storage in the “Run” tab.


Append strings

Let’s make it take a string parameter and append it to storage, then output and store the new value.

parameter string;
return string;
storage string;
code {DUP;DIP{CDR};CAR;CONCAT;DUP;PAIR}

What’s going on here? The CAR and CDR instructions actually modify the top pair (i.e. they are destructive), so we need to duplicate the top pair with DUP if we want to use both elements. The DIP lets us execute a block of code on a deeper element of the stack (we are dipping into the stack, so to say).

In the following section, the first line of code contains type information for elements on the stack and beneath them are my comments detailing the meaning of individual pieces of data.

So the first pair becomes two pairs:

[ pair string string : pair string string ]
       ^      ^             ^      ^
       |      |             |      |
       input  storage       input  storage

Then we dip into the stack:

[ pair string string ]
       ^      ^
       |      |
       input  storage

We pick the second element:

[ string ]
  ^
  |
  storage

We come back from the dip:

[ pair string string : string ]
                       ^
                       |
                       this is the storage

And then we go back to the top and pick the first element:

[ string : string ]
  ^        ^
  |        |
  input    storage

Then we concatenate the strings:

[ string ]
  ^
  |
  result

Duplicate the result:

[ string : string ]
  ^        ^
  |        |
  result   result

And finally, create a new pair:

    [ pair string string ]
           ^      ^
           |      |
return value      new storage

Remember, the first part of the pair is the return value and the second part is the new storage. Try running it!

Something’s still off though – we said we’d like to append the parameter to the storage, not the other way around. The CONCAT simply concatenates the strings, but we need the input parameter to go after the storage. We can use the SWAP instruction to accomplish this – it simply swaps the top two elements of the stack. Find a suitable place to use the instruction and try running the contract again.


Using the command line client

Let’s try to use our alphanet node to run the contracts now, instead of the REPL. If you run into any issues, check the instructions.

NB: You might need to run the commands with sudo.

Start the node with:

./alphanet.sh start

Create a test.tz file with an empty contract:

parameter unit;
return unit;
storage unit;
code {}

Typecheck it to make sure the node works:

./alphanet.sh client typecheck program container:test.tz -details

The details flag will let us see the types of elements after each instruction like in the REPL.

Now that we’ve confirmed that the contract is well typed, we can try running it.

./alphanet.sh client run program container:test.tz on storage Unit and input Unit -trace-stack

The trace-stack flag will let us see the values on the stack during the execution.

Let’s try to run our previous contract that appends strings – create an append.tz file for it. When trying to run the contract from the command line, we need to escape the strings like so:

./alphanet.sh client run program container:append.tz on storage '"Hello"' and input '" world!"'

A neat list of various data types and how to escape them is available at the michelson-lang website.

If you forget the precise syntax of a command, you can use help or man to list available options and commands.

./alphanet.sh client --help
./alphanet.sh client man

That’s it for this article :)

If you liked it, share or discuss it with people who might find it interesting! If there are any mistakes, please let me know (my email address is in the top bar). In the next one, we’ll look at transactions and how to publish contracts to the blockchain.

Getting started with Liquidity 2: authentication

July 31, 2018
easy liquidity cryptocurrency tezos michelson blockchain smart contracts

Getting started with Liquidity: coinflip

May 27, 2018
easy liquidity cryptocurrency tezos michelson blockchain smart contracts

Tezos changes: zeronet update

April 15, 2018
cryptocurrency tezos michelson blockchain smart contracts applications oracles