Smart Contracts: Truffle Suite

in #ethereum7 years ago (edited)

Smart Contract: Truffle Suite.

Truffle Framework

Truffle is the most widely used developer environment and a pipeline framework for writing, testing and deployment of smart contracts on the Ethereum network designed to make life easier.

The truffle suite basically integrates all the necessary tools to get one started, including TestRPC (now known as Ganache) — a local full node simulation for testing our code's behavior before deployment.

Before we proceed to dive in though, let's reiterate through some of the key features of smart contracts and the Solidity language as to better understand the underlying logic of how things work.

Above all, the EVM (Ethereum Virtual Machine) necessitates complete determinism within the smart contract. That means that the same input will always produce the same output so that all nodes could come to a consensus about the state of the blockchain (thus, introducing non-deterministic behavior would make the whole network come to a halt). The idea is to enable people across the globe to do business even if they don't speak the same language or use the same currency (as Ethereum's Mihai Alisie put it). This is why Solidity is a statically typed language where everything must be strictly defined within its proper context.

A contract usually consists of state variables and functions. It's important to distinguish between two categories of functions here:

Read-only functions (designated as "constant") which do not cause any state changes or write to the blockchain, thus require no gas to execute.

Transactional functions, which do perform state changes and therefore spend gas in order to execute and 'write' on the blockchain.

Generally, writing data to the network is called a transaction while reading data is called a call. Transactional functions usually do not return a value, but a transaction id and are not processed immediately until the next block. Calls, on the other hand, are free to execute and immediately return a value.

The gas cost incurred for 'writing' is proportional to the computational work done and is meant to stay constant (i.e., when Ether goes up, the price of gas goes down). This prevents a whole range of attack vectors by making them prohibitively expensive (and with the migration to Proof-of-Stake this year, where the idea is that one risks what one stakes, Vlad Zamfir puts it thus: “if you participate in a failed 51% attack, PoS will burn your ASIC farm down”).

We should also mention that in Ethereum, accounts are identified by an address which is derived differently for external (usually owned by humans) and contract accounts. This is reminiscent of the 'flat ontology' in Actor-Network Theory and the Object-Oriented paradigm of "everything is an object" on an equal ontological footing.

Now, let's get back to Truffle. Make sure you have NodeJS 5.0+ and run the following installation:

$ npm install -g truffle

Next, we spin up a set of default contracts and tests by running the following:

$ mkdir newProject
$ cd newProject
$ truffle init

Our current directory contains a truffle configuration file (truffle.js) and three subdirectories: contracts, migrations and tests (which are self-explanatory).

From there on we can run truffle compile, truffle migrate and truffle test correspondingly to compile our contracts, deploy them to the network and run their associated tests. If not connected to an ethereum client we can run Ganache as a local blockchain simulation (which is ideal for our purposes).

We can also use the Truffle Boxes, which are sets of ready-made interfaces, contracts, libraries, etc. One can find a list of them here.

So, for example, if we wanted to get the OpenZeppelin tutorial box, we'd type the following:

$ truffle unbox tutorialtoken

Another important component is truffle develop which spawns an integrated blockchain environment (running locally on port 9545) generating 10 accounts from a group of easy to remember words (called mnemonic, or mnemonic code/sentence). After launching it, we end up into a console where we can run truffle commands without the truffle prefix:

$ truffle develop
[text showing the accounts and private keys generation]
truffle(develop)>

We use Truffle Develop or Ganache whenever we're testing our project with no intention of immediately deploying on the mainnet and don't need to use or interact with specific accounts (the default development accounts being sufficient for the purposes).

Now let's have a look at our contracts library.
All Solidity contracts, including associated libraries have the file extension .sol.

With a bare Truffle project (truffle init) we have a single Migrations.sol file for helping in the deployment process.

To compile a Truffle project we run truffle compile from the root of the directory where the project is located.
At first run, all contracts will be compiled and subsequently only the contracts that have been changed since last compile (to override this, use the command with the --all option).

Dependencies in Solidity are declared using the import command. For example, if we want to import contracts from another file we must add the following in our code:

import "./SomeContract.sol";

The path is relative to where the current contract being written is localized. Contracts can also be imported from external package repositories (such as EthPM and NPM).

import "somepackage/SomeContract.sol";

After compilation the results will be placed in a build/contracts/ directory.

To run the migrations we run truffle migrate (as already mentioned) — this runs all the migrations located in the projects migrations directory. Migrations are essentially sets of managed deployment scripts in JavaScript format. A simple migration file looks like this:

var MyContract = artifacts.require("NewContract");

module.exports = function(deployer) {
deployment steps//
deployer.deploy(NewContract);
};

The artifacts.require()* method is how we tell Truffle which contracts we want to interact with. The name specified should match the name of the contract as defined in the source file as a single .sol file can contain a number of contracts. To use more than one contract we need artifact.require()* statements for each one:

var ContractOne = artifacts.require("ContractOne");
var ContractTwo = artifacts.require("ContractTwo");

Truffle requires a Migrations contract to take advantage of the Migrations feature — that contract is received by default when creating a new project with truffle init and can be found in contracts/Migrations.sol.

To take advantage of the Migrations feature one must deploy the contract inside his first migration. To do so create a file migrations/1_initial_migration.js which contains the following (migration filenames must begin with numbered prefixes):

var Migrations = artifacts.require("Migrations");

module.exports = function(deployer) {
deployer.deploy(Migrations);
};

From here, you can create new migrations with increasing numbered prefixes (2, 3, 4..) that deploy other contracts.

Truffle also comes with an automated testing framework which allows for writing simple and manageble tests in two ways — in JavaScript (for testing from the outside world) and in Solidity (for more advanced scenarios).

All tests are located in the /test directory, but one can also specify a path:

$ truffle test ./path/to/test/file.js

If just running truffle test this will test all files within /test which have the following extensions: .js, .es, es6, .jsx and .sol.

When running tests against Ganache or Truffle Develop, Truffle utilizes advanced snapshooting features to make sure the test files don't share state with each other.

Further next we'll have a look at contract deployment and oracles for fetching data feeds of events from the outside world.

Coin Marketplace

STEEM 0.19
TRX 0.16
JST 0.030
BTC 67368.20
ETH 2618.26
USDT 1.00
SBD 2.68