Stelios
Stelios Life-long learner, happy father, trying to do some software engineering on the side.

A 'Hello world' Ethereum smart contract using Truffle

A 'Hello world' Ethereum smart contract using Truffle

Continuing from the previous article, I will cover how to use the Truffle framework to facilitate development, testing and deployment of Ethereum smart contracts.

A box of Truffles

Revisiting the previous article on creating a smart contract, we can immediately see a number of things that we would need to have an effective production deployment pipeline.

  • Scaffolding
    Solidity is a relatively new language, which moves pretty fast. Solidity contracts have the additional constraint of complexity being expensive. This makes Solidity programming effectively an optimisation problem. 1
    Therefore creating new contracts needs an easy way to quickly “scaffold” together optimal coding patterns and libraries.

  • Testing
    Although a smart contract is inspired by object-oriented programming (classes encapsulating code and state), initializing one involves deployment to a blockchain. The same applies to resetting the internal state as part of a CI pipeline.
    This calls for a dedicated testing framework.

  • Tracking of smart contracts
    Each deployment of a smart contract (i.e. instantiation) results in a new persistent blockchain address to keep track of.
    In the highly volatile pre-production environments (during active bug fixing and feature addition), tracking many different instances of a smart contract by hand is impossible.

  • Promotion through environments
    This is a corollary of the above. As a contract’s logic evolves and new versions are created, we need a way to keep track what is deployed where. I.e. “our DEV environment has been upgraded, but our UAT not yet”. In addition, most non-trivial applications will require the “co-ordinated” deployment of more than one smart contracts. This will be a familiar concept to people performing database migrations.

Truffle is the answer to all the above; a development framework and testing environment facilitating the SDLC of Ethereum smart contracts.

  • Scaffolding
    Truffle introduces the concept of boxes; a way to quickly initialize a project with Solidity contracts, libraries and front-end code.

  • Testing
    It offers a framework to auto-deploy smart contracts before each test execution to isolate side-effects. Unit testing itself is based on Mocha and Chai.

  • Tracking of smart contracts
    Truffle keeps track of deployed contract addresses across environments. It has the option of a simple file-based mechanism or a more flexible queryable database.

  • Promotion through environments
    Truffle defines a smart contract-based mechanism to follow what has been deployed in which environment (migrations, in Truffle parlance). The mechanism is very similar to what database migration tools use internally. Here Truffle is using the blockchain as a migration state storage mechanism. 2

After this “sales pitch”, let’s install Truffle (e.g. by brew install truffle).

The project

In a new folder, run truffle unbox sgerogia/hello_truffle_box.
This command uses Git to fetch the box project, reads the box descriptor and executes the commands inside it.

This project is a repetition of the ‘Hello world’ contract, built in the previous article. I created a new Truffle project (truffle init), added the Hello contract, along with unit tests and, for ease of use, I packaged it as a box.

Let’s quickly examine the contents of the new project.

  • It has a contracts folder, where we can see Hello.sol (our contract), alongside Migrations.sol (Truffle’s migration supporting contract).
  • The migrations folder contains the commands executed in sequence each time the contract(s) in our project are deployed to an environment.
  • The test folder has 2 examples of Javascript-based unit tests of contracts.
  • Finally, the truffle-config.js contains the ganache network definition pointing to a local running Ganache node.

Compiling

Compiling, testing and deploying are straight-forward command-line operations.

truffle compile is the first thing to do. You will notice that the command creates a build subfolder; this is where Truffle keeps its metadata about the project.

Let’s try running the tests (truffle test).
Passing tests
You will notice that, by default, Truffle is using the test network. This is an in-memory blockchain emulator, using the same engine as the Ganache app.

Changing the assertion in one of the tests, will yield an error like the following
Failing test

Deploying

Let’s deploy the contracts to our Ganache app and see what happens behind the scenes.

First we need to create a clean Ganache workspace (or reset an existing one).
New workspace

In a terminal running in our project’s folder, let’s migrate our contract.
truffle migrate --network ganache
We can see the results of the deployment of the 2 contracts: first Migrations, then Hello.
Truffle migrate output

By default, Truffle is using the first account it finds in Ganache to perform the deployments (and charge for the cost in ether).
Ganache accounts

Going into the Transactions tab of Ganache, we can inspect what has happened on the blockchain. The transactions appear newer first.
truffle migrate transactions
We can see that we have

  • 2 “contract creation” transactions, for the 2 deployed contracts, and
  • 2 “contract call” transactions. We will see what these are in the next section, where we are…

Interacting with the contracts

In the same project folder, let’s open a new terminal with a Truffle console
truffle console --network ganache
This loads an “enhanced” Node.js console, with some convenient abstractions over the Web3 library.

First let’s see what those 2 “contract call” transactions where. Let’s type

1
2
Migrations.deployed().then(function(instance) {migrationsApp = instance;})
migrationsApp.last_completed_migration().then(function(result){return result.toNumber();})

Calling Migrations contract
We can see that the value of the last_completed_migration field is 2. This corresponds to the filename prefix of the migrations files. It tells Truffle “next time you migrate for this project and blockchain environment, continue from this file”. In other words the numeric part of the filename is for Truffle, the rest is for readability.

Now let’s call our own contract, by typing

1
2
Hello.deployed().then(function(instance) {helloApp = instance;})
helloApp.getMessage()

Calling Hello contract
Getting the value is much more straight-forward when in the context of Truffle.

Finally, let’s update the contract’s value.
helloApp.setMessage("Hello from Truffle!", {from: accounts[1]}).then(function() {return helloApp.getMessage();})
We are calling the contract from the 2nd account in Ganache (accounts[1]). Because updating the contract’s state involves mining a block (i.e. some delay), we verify the updated value (helloApp.getMessage()) inside the return of the promise.

Parting thought

And that’s it!
In this post we got a taste of the Truffle framework and how it facilitates the SDLC of smart contract programming.

Happy coding!

Footnotes

  1. Let’s contrast this with the opposite trend in cloud computing.
    The falling cost of compute (compared to cost of engineering time) makes code optimisations almost an after-thought.
  2. An instance of “eat your own dog food”.

comments powered by Disqus