Truffle Suite is the tool pack dedicated to Ethereum developers (focusing on smart contracts). That very actively developed project is currently one of the most popular frameworks for implementing, testing and running Ethereum based decentralized applications.
In this article:
- I will describe the Truffle Suite tools;
- I will describe and use the main tool of the suite – Truffle (name of the tool is the same as suite name);
- I will initialize example project Pet Shop – implementing first features and corresponding tests;
Truffle Suite
Truffle Suite currently consist of 3 components dedicated for Ethereum developers. These are:
- Truffle – the tool dedicated to creation Ethereum based project structure. It creates the basic folders structure, it manages the dependencies, allows to implement automated tests and finally to run the the code.
- Ganache – personal, local Ethereum blockchain (the simulator). It allows to run implemented contracts (and tests).
- Drizzle – the collection of frontend libraries which makes dapps UI development easier.
These tools are collectively the suite because all together they improve and help development of all the layers of decentralized application (the smart contract layer which is backend, and UI – the frontend). These tools must be installed in operating system what makes the impossible to use in web code editors. Truffle Suite (except Drizzle) is similar to Remix IDE, or newer Ethereum Studio which also allow to edit, compile and run smart contracts. The benefits of using Truffle Suite is simply the possibility of using own choice IDE and possibilities in the space of automation and scripting (for example automated testing or compilation).
Truffle Suite currently consists of 3 components for developers: Truffle tool, Ethereum blockchain simulator – Ganache and frontend libraries for dapps development – Drizzle.
Truffle tool – what’s the purpose?
Truffle is the main tool of the Truffle Suite. Its functionalities allow for extensive Ethereum based project development. It structures the project improving the maintainability. It also allows testing and running the contracts, including complex deployment scenarios. So far it’s experimental but you can even debug smart contracts using Truffle. This tool is the framework of smart contracts development – the model of using the tool and maintaining the project is set and fixed. The project initialized with that tool consists of:
- contracts catalog – where the smart contracts source code files are stored.
- migrations catalog – it contains the migrations files. Migrations are the instructions of compiling and running (to the blockchain) smart contracts. They makes the compilation easy, especially when we talk about large projects which consist of multiple files and dependencies (for example other contracts which are already loaded in the blockchain network).
- tests catalog – where the automated test files are stored. Truffle allows to implement tests using Javascript or Solidity.
This tool is based on Node.js which is why dependencies management is based on npm. Project configuration files and the migration definitions are based on Javascript.
Installation
The installation uses npm. In order to install the tool in the Linux system, simply run:
npm install truffle -g
It’s possible that it must be run with sudo
(it depends of OS configuration).
Part of the Truffle tool package is also the Solidity compiler this is why there is no need to additionally install it. After the successful installation truffle
command should be available.
How it works? Let’s initialize the Pet Shop project
Truffle has kind of library of already prepared projects (called boxes), which can be used by developers. These already prepared and setup projects can be useful when we develop the dapp having similar functionality to the example project or when we have similar technology stack. This box will have all dependencies set what makes less work for developer. The boxes list has already over a dozen of projects.
Having Truffle installed it’s possible to download and extract box project. Installation is simply based on invoking the command:
truffle unbox pet-shop
This particular command downloads the example Pet Shop project. The structure of this project opened in the IDE is given (Intellij used with Intellij-Solidity plugin):
Project has the described previously folders structure. By default Truffle is dedicated to Solidity smart contracts however it’s possible to download Vyper programming language based project.
Currently there is only 1 contract Migrations.sol
and 1 migration Javascript file 1_initial_migration.js
. These 2 files together create the mechanism of compilation and deployment of the project so should not be deleted.
Smart contract
The smart contract being the logic of developed Pet Shop is in the single file (I created the file contracts/Adoption.sol
). Its code is given:
pragma solidity ^0.5.0; contract Adoption { address[16] public adopters; function adopt(uint petId) public returns (uint) { require(petId >= 0 && petId <=15); adopters[petId] = msg.sender; return petId; } function getAdopters() public view returns (address[16] memory) { return adopters; } }
Contract defines the array which can store 16 address
type elements. Has 2 public functions: adopt
and getAdopters
.
The function adopt
changes the inner state of the contract by doing the logic of ‘adopting’ – assigning the address of function caller to the array under the given index petId
. The second line of this function restricts the possibility of assigning the value to the array index beyond the correct index (array has 16 elements so it can store values under index 0-15). The lack of this secure mechanism would be really serious flaw and bug. The function returns the value of parameter which also accepts (petId
). It uses 8 bit unsigned integer type – because we store quite small value it’s appropriate type to use.
The function getAdopters
has the keyword view
in its declaration. The view
functions indicate that the logic of the function doesn’t change the inner state of the smart contract. It means it’s impossible to assign the value to any contract fields. Trying for example to move logic from adopt
function to this function returns given compilation error: TypeError: Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
Compilation of the contract is simply invoking the command:
truffle compile
Invoking the command causes the contract compilation – the build
catalog will be generated. The folder includes .json
files, the file per contract. These files contains among the others: compiled contract bytecode, ABI (Application Binary Interface) and some other data which enable Truffle to run tests and interact with contract from test environment.
Migration
The Adoption
contract migration code is in the file I’ve created migrations/2_deploy_contracts.js
. The code is given:
const Adoption = artifacts.require('Adoption'); module.exports = function(deployer) { deployer.deploy(Adoption); };
Truffle is based on Node.js this is why we can use require
keyword in order to “import” the contracts/Adoption.sol
contract and assign it to Adoption
constant variable. The migration is quite simple because Adoption
contract has no dependencies.
Defined migration can be now invoked (what will cause loading contract to the blockchain). It’s done by invoking the command:
truffle migrate
The result of the command is printed on the console and contains the information about the successful migration, in particular: the hash of contract deployment transaction or the gas cost. The Truffle network configuration by default recognizes the Ganache
simulator running. Configuring the Ethereum testnet is defined in truffle-config.js
.
Tests
The implementation of automated tests using Truffle is based on 2 options:
- tests using Javascript (or Typescript) – in that scenario the test engine is Mocha, assertion library is Chai;
- tests using Solidity – the mechanism of Truffle allows to implement which are smart contracts running in the same blockchain environment where the contract being tested. This implies the direction communication between test contract and tested contract;
Javascript tests based on popular technology stack will be probably good choice for developer who is already familiar with that language and the stack (JS/Mocha/Chai). I also think that JS tests are beneficial in the sense of testing correct conversion of types between Solidity and Javascript, having in mind that implementing true dapp with web interface is based on Javascript (web3.js).
The benefits of using Solidity based contracts is the minimalistic approach of these tests (very few dependencies) and complexity of the project. Everything what needed is already provided by Truffle – the tests initialization mechanism and assertion libraries. Also what I believe is that writing Solidity more is always good way to learn the language and the technology overall.
Testing the contracts in Truffle, no matter of the testing technology of choice is always the interaction directly with smart contract (running in blockchain). Before starting tests the contract is loaded to the network (e.g. testnet network or Ganache). Because of that, these are not unit tests for whose the result of invocation is the code processing in isolated local environment. What’s worth to mention that every test invocation causes reloading the tested contract to the network (it’s also truth for Solidity based contracts tests). In fact this makes tests running in “isoloated” environment however only because this integration with blockchain – these tests cannot be described as unit tests. And once again: because tests run in the blockchain, you should better be careful testing on e.g. Ethereum testnet (where the deployment is simply “gas” cost).
Truffle gives possibility to implement automated tests using Javascript (Mocha/Chai) and Solidity. The tests interact directly with smart contract running in blockchain (for example in testnet or Ganache).
The following code is the example simple test contract (implemented in Solidity) for the Adoption
contract features. It tests 2 functions from Adoption
:
pragma solidity ^0.5.0; import "truffle/Assert.sol"; import "truffle/DeployedAddresses.sol"; import "../contracts/Adoption.sol"; contract TestAdoption { Adoption adoption = Adoption(DeployedAddresses.Adoption()); uint expectedPetId = 8; address adopterId = address(this); function testShouldAdoptCorrectlyAndReturnExpectedAdoptionId() public { //when uint returnedId = adoption.adopt(expectedPetId); //then Assert.equal(returnedId, expectedPetId, "Returned adoption ID should match expected id!"); } function testShouldReturnCorrectAdopters() public { //when address[16] memory adopters = adoption.getAdopters(); //then for (uint i = 0; i< adopters.length; i++) { if (i == expectedPetId) { Assert.equal(adopters[i], adopterId, "Expected adopter address under adopted pet id!"); } else { Assert.equal(uint(adopters[i]), uint(0), "Expected no adopter!"); } } } }
The code is quite hermetic, and 2 imports and the beginning initialize the test and deliver all required assertions. The test contracts names in Truffle must start with the Test
prefix and test functions must start with test
prefix. Running the test (what requires configured blockchain network running) is simply:
truffle test
Summary
Growing Ethereum ecosystem continuously delivers more and more tools dedicated for developers. Truffle, the main tool of Truffle Suite is the framework for implementation, testing and running Ethereum smart contracts. Open source, price (Truffle is a free tool), community support, a lot of features and stability – these are at least few of attributes which will be taken under consideration by potential users. It’s worth to have these attributes in mind, especially when developing blockchain solutions. There are of course known software development problems like technical overhead, risk and costs of choosing particular technology but except that, we deal with much more strict approach of immutability of blockchain where the cost of unexpected behavior (or bug) can be really huge.
Do you use Truffle in your projects? Do you know some alternative tools? Have some opinion or you know some fancy feature of Truffle?
Let me know in the comments! Przemek